﻿using JESAI.HtmlTemplate.Pdf;
#if !NET45
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.DependencyInjection;
#else
using System.Web.Mvc;
using System.Web;
#endif
using RazorEngine.Compilation.ImpromptuInterface.Optimization;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JESAI.HtmlTemplate.Pdf.Utils;

namespace Microsoft.AspNetCore.Mvc
{
    public class PDFCallResult<T> : ActionResult where T:class
    {
        private const string ActionNameKey = "action";
        public T Value { get; private set; }
        public Func<byte[], byte[]> _func { get; private set; }
        public string FileRootPath { get; private set; }= "D:\\PdfFile";
        public string FileName { get; private set; }
        public bool IsSaveFile { get; private set; }
        public PDFCallResult(T value,Func<byte[], byte[]> func,bool isSaveFile=true ,string fileName=null,string fileRootPath=null)
        {
            Value = value;
            _func = func;
            FileName = fileName;
            IsSaveFile = isSaveFile;
            if (!string.IsNullOrWhiteSpace(fileRootPath))
            {
                FileRootPath = fileRootPath;
            }
        }
        //public override async Task ExecuteResultAsync(ActionContext context)
        // {
        //     var services = context.HttpContext.RequestServices;
        //    // var executor = services.GetRequiredService<IActionResultExecutor<PDFResult>>();
        //     //await executor.ExecuteAsync(context, new PDFResult(this));
        // }
#if !NET45
        private static string GetActionName(ActionContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (!context.RouteData.Values.TryGetValue(ActionNameKey, out var routeValue))
            {
                return null;
            }

            var actionDescriptor = context.ActionDescriptor;
            string normalizedValue = null;
            if (actionDescriptor.RouteValues.TryGetValue(ActionNameKey, out var value) &&
                !string.IsNullOrEmpty(value))
            {
                normalizedValue = value;
            }

            var stringRouteValue = Convert.ToString(routeValue, CultureInfo.InvariantCulture);
            if (string.Equals(normalizedValue, stringRouteValue, StringComparison.OrdinalIgnoreCase))
            {
                return normalizedValue;
            }

            return stringRouteValue;
        }
#endif

#if !NET45
        public override async Task ExecuteResultAsync(ActionContext context)
          {
            var viewName = GetActionName(context);
            var services = context.HttpContext.RequestServices;
            var exportPdfByHtmlTemplate=services.GetService<IExportPdfByHtmlTemplate>();
            var viewEngine=services.GetService<ICompositeViewEngine>();
            var tempDataProvider = services.GetService<ITempDataProvider>();
            var result = viewEngine.FindView(context, viewName, isMainPage: true);
#else
        public override void ExecuteResult(ControllerContext context)
        {
            var viewName = context.RouteData.Values["action"].ToString();
            var result = ViewEngines.Engines.FindView(context, viewName, null);
            context.HttpContext.Response.Clear();
            IExportPdfByHtmlTemplate exportPdfByHtmlTemplate = new PdfByHtmlTemplateExporter ();
#endif
            if (result.View == null)
                throw new ArgumentException($"名称为：{viewName}的视图不存在，请检查!");
           
             context.HttpContext.Response.ContentType = "application/pdf";
            //context.HttpContext.Response.Headers.Add("Content-Disposition", "attachment; filename=test.pdf");                    
            var html = "";
            using (var stringWriter = new StringWriter())
            {                            
#if !NET45
                var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { Model = Value };
                var viewContext = new ViewContext(context, result.View, viewDictionary, new TempDataDictionary(context.HttpContext, tempDataProvider), stringWriter, new HtmlHelperOptions());

                await result.View.RenderAsync(viewContext);
#else
                var viewDictionary = new ViewDataDictionary(new ModelStateDictionary()) { Model = Value };
                var viewContext = new ViewContext(context, result.View, viewDictionary, context.Controller.TempData, stringWriter);
                result.View.Render(viewContext, stringWriter);
                result.ViewEngine.ReleaseView(context, result.View);
#endif
                html = stringWriter.ToString();

            }
            byte[] buff = new byte[] { };
            if (IsSaveFile)
            {
                if (!Directory.Exists(FileRootPath))
                    Directory.CreateDirectory(FileRootPath);
                var hashCode = MD5HashUtil.GetMD5HashString(Value);
                var filePath = FileRootPath + "\\" + hashCode + (FileName ?? "") + ".pdf";
             
                //var tpl=File.ReadAllText(result.View.Path);
#if !NET45
                //byte[] buff=await exportPdfByHtmlTemplate.ExportByHtmlPersistAsync<T>(Value,html);
                if (File.Exists(filePath))
                    buff = await File.ReadAllBytesAsync(filePath);
                else
                {
                    buff = exportPdfByHtmlTemplate.ExportByHtmlAsync<T>(html).Result;
                    buff = _func.Invoke(buff);
                    await File.WriteAllBytesAsync(filePath, buff);
                }
#else


            if (File.Exists(filePath))
                buff=File.ReadAllBytes(filePath);
            else
            {
                buff =  exportPdfByHtmlTemplate.ExportByHtml<T>(html);
                buff = _func.Invoke(buff);
                File.WriteAllBytes(filePath, buff);
            }

#endif
            }
            else
            {
#if !NET45
                buff = exportPdfByHtmlTemplate.ExportByHtmlAsync<T>(html).Result;
                buff = _func.Invoke(buff);
#else
                buff =  exportPdfByHtmlTemplate.ExportByHtml<T>(html);
                buff = _func.Invoke(buff);
#endif
            }

#if NET45
            context.HttpContext.Response.AddHeader("Content-Length", buff.Length.ToString());
            context.HttpContext.Response.AddHeader("Content-Disposition", "filename=电子签章PDF-"+DateTime.Now.ToString()+".pdf");
            context.HttpContext.Response.BinaryWrite(buff);
            context.HttpContext.Response.Flush();
            context.HttpContext.Response.Close();
            context.HttpContext.Response.End();

#else
            context.HttpContext.Response.Headers.Add("Content-Length", buff.Length.ToString());
            using (MemoryStream ms = new MemoryStream(buff))
            {
                byte[] buffer = new byte[0x1000];
                while (true)
                {
                    int count = ms.Read(buffer, 0, 0x1000);
                    if (count == 0)
                    {
                        return;
                    }
                    await context.HttpContext.Response.Body.WriteAsync(buffer, 0, count);
                }
            }
#endif
        }
    }
}
